window.onload = function () {

    var Audio = {
        BA: gm("#Background-AudioPlayer")[0],
        SA: gm("#Score-AudioPlayer")[0],
        GA: gm("#GameOver-AudioPlayer")[0]
    };
	
    function Game() {

        this.scoreEle = gm("#scores");
        this.timer = null;
        this.map = null;
        this.block = null;
        var that = this;

        this.init = function () {
            var content = "Welcome to tetris!";
            gm("#greeting").html(content);
        };

        this.start = function () {
            gm("#info").hide();
            that.scoreEle.val(0);
            that.map = new Map(12, 15);
            that.map.init();
            that.block = new Block(that.map.cols, that.map.rows, that.map.blockArray);
            that.block.newBlock();
            that.timer = window.setInterval(that.block.GoDown, 1000);
        };

        this.pause = function () {
            window.clearInterval(that.timer);
            that.timer = null;
            Audio.BA.pause();
            gm("document").keydown = null;
            var content = "<h2 style='margin:100px auto'>Game pause!</h2>";
            gm("#info").html(content).show();
        };

        this.resume = function () {
            gm("#info").hide();
            that.timer = window.setInterval(that.block.GoDown, 1000);
            Audio.BA.play();
        };

        this.addScore = function (value) {
            that.scoreEle.val(parseInt(that.scoreEle.val()) + value);
        };

        this.finish = function finish() {
            window.clearInterval(that.timer);
            gm("document").keydown = null;
            that.scoreEle.val(0);
            Audio.BA.pause();
            Audio.GA.play();
            window.alert("Game over!");
            window.location.reload();
            return;
        };

    }


    function Map(cols, rows) {

        this.cols = cols;
        this.rows = rows;
		this.blockArray = [];
        var bckArr = this.blockArray;

        var i = 0, j = 0;
        this.init = function () {
            for (i = 0; i < rows; i++) {
                bckArr[i] = [];
                for (var j = 0; j < cols; j++) {
                    bckArr[i][j] = gm("<div>");
                    bckArr[i][j].css({'top': i * 8 + 1 + "vw"});
                    bckArr[i][j].css({'left': j * 8 + 1 + "vw"});
                    bckArr[i][j].attr({"class": "plaint"});
                    gm("#map").append(bckArr[i][j]);
                }
            }
            Audio.BA.play();
        };

    }


    function Block(cols, rows, blockArray) {

        this.currentBlock = { type: 0, cells: [] };
        var that = this;
		var currentBlock = this.currentBlock;
		var blockArray = game.map.blockArray;

        this.newBlock = function newBlock() {
			var self = this;
            type = Math.ceil(Math.random() * 5);
            currentBlock.type = type;
            switch (type) {
                case 1:
                    currentBlock.cells = [[0, cols / 2 - 2], [0, cols / 2 - 1], [0, cols / 2], [0, cols / 2 + 1]];
                    break;
                case 2:
                    currentBlock.cells = [[0, cols / 2 - 2], [0, cols / 2 - 1], [0, cols / 2], [1, cols / 2 - 2]];
                    break;
                case 3:
                    currentBlock.cells = [[1, cols / 2 - 1], [1, cols / 2], [1, cols / 2 + 1], [0, cols / 2]];
                    break;
                case 4:
                    currentBlock.cells = [[0, cols / 2 - 1], [0, cols / 2], [1, cols / 2 - 1], [1, cols / 2]];
                    break;
                case 5:
                    currentBlock.cells = [[0, cols / 2 - 1], [0, cols / 2], [1, cols / 2], [1, cols / 2 + 1]];
                    break;
            }
            for (var i = 0; i < currentBlock.cells.length; i++) {
                if (blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1]].hasClass("fixed")) {
                    game.finish();
                }
            }
            for (i = 0; i < currentBlock.cells.length; i++) {
                blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1]].attr({"class" : "active"});
            }
        };


        this.GoDown = function GoDown() {
            var i = 0;
            for (i = 0; i < currentBlock.cells.length; i++) {
                if (currentBlock.cells[i][0] + 1 == rows || blockArray[currentBlock.cells[i][0] + 1][currentBlock.cells[i][1]].hasClass("fixed")) {
                    for (i = 0; i < currentBlock.cells.length; i++) {
                        blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1]].attr({"class" : "fixed"});
                    }
                    that.newBlock();

                    var fullLines = that.GetFullLine();
                    if (fullLines.length) {
                        that.clearLines(fullLines);
                        game.addScore(fullLines.length);
                    }
                }
            }
            that.clear();

            for (i = 0; i < currentBlock.cells.length; i++) {
                currentBlock.cells[i][0]++;
            }

            that.fresh();
        };


        this.GetFullLine = function GetFullLine() {
            var aResult = [];
            for (var i = 0; i < rows; i++) {
                var count = 0;
                for (var j = 0; j < cols; j++) {
                    if (blockArray[i][j].hasClass("fixed")) { count++; }
                    if (count == cols) { aResult.push(i); }
                }
            }
            return aResult;
        };

        this.clear = function clear() {
            for (var i = 0; i < currentBlock.cells.length; i++) {
                blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1]].attr({"class" : "plaint"});
            }
        };

        this.fresh = function fresh() {
            for (var i = 0; i < currentBlock.cells.length; i++) {
                blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1]].attr({"class" : "active"});
            }
        };

        this.clearLines = function clearLines(arg) {
            for (i = 0; i < arg.length; i++) {
                for (j = arg[i]; j > 0; j--) {
                    for (k = 0; k < cols; k++) {
                        blockArray[j][k].attr({"class" : blockArray[j - 1][k].attr("class")});
                    }
                }
            }
            Audio.SA.play();
        };

        this.checkLeft = function checkLeft() {
            for (var i = 0; i < currentBlock.cells.length; i++) {
                if (currentBlock.cells[i][1] <= 0 || blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1] - 1].hasClass("fixed")) {
                    return false;
                }
            }
            return true;
        };

        this.checkRight = function checkRight() {
            for (var i = 0; i < currentBlock.cells.length; i++) {
                if (currentBlock.cells[i][1] >= cols - 1 || blockArray[currentBlock.cells[i][0]][currentBlock.cells[i][1] + 1].hasClass("fixed")) {
                    return false;
                }
            }
            return true;
        };

        this.ration = function ration() {
            var cBlock = [];
            var i = 0;
            for (i = 0; i < currentBlock.cells.length; i++) {
                cBlock[i] = currentBlock.cells[i];
            }
            if (currentBlock.type == 4) {
                return;
            } else {
                var tmp = 0;
                var gapX = cBlock[1][1] - 0;
                var gapY = cBlock[1][0] - 0;
                for (i = 0; i < cBlock.length; i++) {
                    cBlock[i][1] -= gapX;
                    cBlock[i][0] -= gapY;
                }
                for (i = 0; i < cBlock.length; i++) {
                    tmp = cBlock[i][0];
                    cBlock[i][0] = cBlock[i][1];
                    cBlock[i][1] = -tmp;
                }
                for (i = 0; i < cBlock.length; i++) {
                    cBlock[i][1] += gapX;
                    cBlock[i][0] += gapY;
                }
                for (i = 0; i < cBlock.length; i++) {
                    if (cBlock[i][0] < 0 || cBlock[i][0] >= rows || cBlock[i][1] < 0 || cBlock[i][1] >= cols || blockArray[cBlock[i][0]][cBlock[i][1]].hasClass("fixed")) {
                        return;
                    }
                }
                for (i = 0; i < cBlock.length; i++) {
                    currentBlock.cells[i] = cBlock[i];
                }
            }
        };

        gm("document").keydown(function (e) {
            switch (e.keyCode) {
                case 65:
                    if (that.checkLeft()) {
                        that.clear();
                        for (i = 0; i < currentBlock.cells.length; i++) {
                            currentBlock.cells[i][1]--;
                        }
                        that.fresh();
                    }
                    break;
                case 68:
                    if (that.checkRight()) {
                        that.clear();
                        for (i = 0; i < currentBlock.cells.length; i++) {
                            currentBlock.cells[i][1]++;
                        }
                        that.fresh();
                    }
                    break;
                case 83:
                    that.GoDown();
                    break;
                case 87:
                    that.clear();
                    that.ration();
                    that.fresh();
                    break;
                default:
                    break;
            }
        });
        //aspect buutons controller
        gm("button.aspect:nth-child(1)").bind("click", function () {
            if (that.checkLeft()) {
                that.clear();
                for (i = 0; i < currentBlock.cells.length; i++) {
                    currentBlock.cells[i][1]--;
                }
                that.fresh();
            }
        });
        gm("button.aspect:nth-child(2)").bind("click", function () {
            that.clear();
            that.ration();
            that.fresh();
        });
        gm("button.aspect:nth-child(3)").bind("click", function () {
            if (that.checkRight()) {
                that.clear();
                for (i = 0; i < currentBlock.cells.length; i++) {
                    currentBlock.cells[i][1]++;
                }
                that.fresh();
            }
        });
        gm("button.aspect:nth-child(4)").bind("click", function () {
            that.GoDown();
        });
    }

    //command and control
    var game = null;
    game = new Game();
    game.init();

    gm("#startBtn").bind("click", function () {
        game.start();
    });

    gm("#pauseBtn").on("click", function () {
        game.pause();
    });

    gm("#resumeBtn").on("click", function () {
        game.resume();
    });

    gm("#endBtn").on("click", function () {
        game.finish();
    });
};